package pl.smath.parser.text;

/**
 * Returns tokens based on the list.
 * If character in input is not on the token list then it is returned as symbol.

 * @author Krzysztof Langner
 */
class Tokenizer {

	private static final String[] OPERATORS = {
		"+", "-", "*", "/", "^",
		"(", ")", 
		"=", ">", "<", ">=", "=<" 
	};
	
	private String  input;
	private int		index;
	private Token	pushbackToken;
	
	
	/**
	 * constructor
	 * @param in
	 */
	public Tokenizer(String in){
		
		input = in.trim();
		index = 0;
		pushbackToken = null;
	}

	
	/**
	 * Check if there are more tokens
	 */
	public boolean hasMoreTokens(){
		
		return (pushbackToken != null || index < input.length());
	}

	
	/**
	 * Return token and move pointer to the next one
	 */
	public Token nextToken(){
		
		Token 	token;
		String	in;
		
		if(pushbackToken != null){
			token = pushbackToken;
			pushbackToken = null;
			return token;
		}
			
		// Remove white spaces
		while(index < input.length() && input.charAt(index) == ' ')
			index ++;
			
		if(!hasMoreTokens())
			return null;
		
		in = input.substring(index);

		// try operator
		token = readOperator(in);
		
		// Try number
		if(token == null)
			token = readNumber(in);

		// try symbol
		if(token == null)
			token = readSymbol(in);

		return token;
	}
	
	
	/**
	 * Cofniecie ostatnio pobranego tokena
	 * @param token
	 */
	public void pushback(Token token){
		pushbackToken = token;
	}
	

	/**
	 * Próbuje zintepretować dane wejściowe jako operator.
	 * Jeżeli nie ma operatora na wejściu to zwraca null
	 */
	private Token readOperator(String in){

		for(String op : OPERATORS){
			
			if(in.startsWith(op)){
				index += op.length();
				return new OperatorToken(op);
			}
		}
		
		return null;
	}
	
	/**
	 * Próbuje zintepretować dane wejściowe jako liczbe.
	 * Jeżeli nie ma liczby na wejściu to zwraca null
	 */
	private Token readNumber(String in){

		int i = 0;
		
		while( i < in.length() && 
				(Character.isDigit(in.charAt(i)) || in.charAt(i) == '.') )
		{
			i++;
		}
		
		if(i > 0){
			index += i;
			return new NumberToken(in.substring(0, i));
		}
		
		return null;
	}
	
	/**
	 * Próbuje zintepretować dane wejściowe jako symbol.
	 * Jeżeli nie ma symbolu na wejściu to zwraca null
	 */
	private Token readSymbol(String in){

		int i = 0;
		
		while( i < in.length() && Character.isLetter(in.charAt(i)) )
		{
			i++;
		}
		
		if(i > 0){
			index += i;
			return new SymbolToken(in.substring(0, i));
		}
		
		return null;
	}
}
